﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
using Hxsoft.AppV1;

namespace Hxsoft.AppV1.Module
{
	public partial class Site
	{
		private LoadedValue<string[]> loadedDomains;
		/// <summary>
		/// 站点的域名列表。
		/// </summary>
		public string[] Domains
		{
			get
			{
				if(loadedDomains.Loader == null)
					loadedDomains.Loader = () => string.IsNullOrEmpty(Domain) ? new string[] { } : StringExtensions.CasingDecompound<string>(Domain, Sites.DomainSeparator, StringSplitOptions.RemoveEmptyEntries);
				return loadedDomains.Value;
			}
			set
			{
				Domain = StringExtensions.CasingCompound(value, Sites.DomainSeparator, StringSplitOptions.RemoveEmptyEntries);
				loadedDomains.ResetValue();
			}
		}
		
		/// <summary>
		/// 站点的主域名。
		/// </summary>
		public string MainDomain
		{
			get
			{
				var domains = Domains;
				if (domains == null || domains.Length == 0)
					return null;
				return domains[0];
			}
		}
	}




	/// <summary>
	/// Sites 类。
	/// </summary>
	public static partial class Sites
	{
		public const string INFO_TYPE = "Site";
		public const string OwnedSitesSeparator = ",";
		public const string DomainSeparator = "\n";



		#region Helper
		/// <summary>
		/// 构建所属站点字符串。
		/// </summary>
		/// <param name="siteIds">原所属站点字符串。</param>
		/// <returns>构建的所属站点字符串。</returns>
		public static string BuildOwnedSiteIds(string siteIds)
		{
			return Hxsoft.StringExtensions.Pack(siteIds, OwnedSitesSeparator);
		}

		/// <summary>
		/// 构建所属站点字符串。
		/// </summary>
		/// <param name="siteIds">所属站点集合。</param>
		/// <returns>构建的所属站点字符串。</returns>
		public static string BuildOwnedSiteIds(ICollection<int> siteIds)
		{
			return BuildOwnedSiteIds(Hxsoft.StringExtensions.Compound(siteIds, OwnedSitesSeparator));
		}

		/// <summary>
		/// 构建所属站点字符串。
		/// </summary>
		/// <param name="siteId">进行构建的站点标识。</param>
		/// <returns>构建的所属站点字符串。</returns>
		public static string BuildOwnedSiteIds(int siteId)
		{
			return BuildOwnedSiteIds(siteId.ToString());
		}

		/// <summary>
		/// 获取所属站点字符串中的站点列表字符串。
		/// </summary>
		/// <param name="ownedSiteIds">所属站点。</param>
		/// <returns>所属站点字符串中的站点列表字符串。</returns>
		public static string GetOwnedSiteIdsSiteIds(string ownedSiteIds)
		{
			return Hxsoft.StringExtensions.Unpack(ownedSiteIds, OwnedSitesSeparator);
		}

		/// <summary>
		/// 分解所属站点标识。
		/// </summary>
		/// <param name="siteIds">进行分解的所属站点。</param>
		/// <returns>分解后的所属站点标识集合。</returns>
		public static int[] DecompoundOwnedSiteIds(string siteIds)
		{
			return Hxsoft.StringExtensions.Decompound<int>(siteIds, OwnedSitesSeparator, StringSplitOptions.RemoveEmptyEntries);
		}
		#endregion



		#region GetItems
		public static List<Site> GetItems()
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;
			return dc.Sites.GetItems();
		}

		public static List<Site> GetItems(this System.Data.Linq.Table<Site> o)
		{
			return o.ToList();
		}



		public static List<Site> GetItems(int[] siteIds)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;
			return dc.Sites.GetItems(siteIds);
		}
		
		public static List<Site> GetItems(this System.Data.Linq.Table<Site> o, int[] siteIds)
		{
			return o.Where(p => siteIds.Contains(p.SiteId)).ToList();
		}
		#endregion



		#region GetItem
		public static Site GetItem(int siteId)
		{
			Dictionary<int, Site> sites = GenericCacheContainer.Instance.SiteDictionary;
			if (sites.ContainsKey(siteId))
				return sites[siteId];

			lock (sites)
			{
				if (!sites.ContainsKey(siteId))
				{
					GenericModuleDataContext dc = new GenericModuleDataContext();
					dc.ObjectTrackingEnabled = false;
					Site value = dc.Sites.GetItem(siteId);
					if (value == null) return null;
					try
					{
						sites[siteId] = value;
					}
					catch (IndexOutOfRangeException err)
					{
						sites.Clear();
						sites[siteId] = value;
					}
				}
			}
			return sites[siteId];
		}

		/// <summary>
		/// 根据标识获取指定的站点。
		/// </summary>
		/// <param name="o">站点集合。</param>
		/// <param name="siteId">获取的站点标识 SiteId。</param>
		/// <returns>获取的信息项。</returns>
		public static Site GetItem(this System.Data.Linq.Table<Site> o, int siteId)
		{
			return o.SingleOrDefault(p => p.SiteId == siteId);
		}

		public static string GetSiteName(int siteId)
		{
			Site site = GetItem(siteId);
			if (site != null) return site.SiteName;
			return null;
		}

		public static string GetSiteName(this System.Data.Linq.Table<Site> o, int siteId)
		{
			return (from p in o
					where p.SiteId == siteId
					select p.SiteName).SingleOrDefault();
		}
		#endregion



		#region CurrentSiteId
		public static int? CurrentSiteId
		{
			get { return App.Context.CurrentSiteId; }
		}

		public static string CurrentSiteName
		{
			get
			{
				Site site = App.Context.CurrentSite;
				return site == null ? string.Empty : site.SiteName;
			}
		}
		#endregion



		#region GetSiteByDomain
		public static Site GetSiteByDomain(this System.Data.Linq.Table<Site> o, string domain)
		{
			return o.FirstOrDefault(p => p.Domain.Contains(DomainSeparator + domain.Trim() + DomainSeparator));
		}

		public static Site GetSiteByDomain(string domain)
		{
			Dictionary<string, Site> sites = GenericCacheContainer.Instance.CurrentSiteDictionary;
			if (sites.ContainsKey(domain))
				return sites[domain];

			lock (sites)
			{
				if (!sites.ContainsKey(domain))
				{
					GenericModuleDataContext dc = new GenericModuleDataContext();
					dc.ObjectTrackingEnabled = false;
					Site value = dc.Sites.GetSiteByDomain(domain);
					if (value == null) return null;
					try
					{
						sites[domain] = value;
					}
					catch (IndexOutOfRangeException err)
					{
						sites.Clear();
						sites[domain] = value;
					}
				}
			}
			return sites[domain];
		}
		#endregion



		#region Exists
		/// <summary>
		/// 验证指定的站点是否已经存在。
		/// </summary>
		/// <param name="o">站点集合。</param>
		/// <param name="siteId">验证的站点标识 SiteId。</param>
		/// <returns>布尔值表示指定的站点是否已经存在。</returns>
		public static bool Exists(this System.Data.Linq.Table<Site> o, int siteId)
		{
			return o.Any(p => p.SiteId == siteId);
		}
		#endregion
	}



	/// <summary>
	/// Sites 类操作部分。
	/// </summary>
	public static partial class Sites
	{
		#region Insert
		/// <summary>
		/// 添加站点。
		/// </summary>
		/// <param name="insertedSite">添加的站点。</param>
		/// <returns>添加的站点。</returns>
		public static Site Insert(Site insertedSite)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Site site = insertedSite.ToNewEntity<Site>();
			site.Domain = site.Domain == null ? null : site.Domain.Replace("\r\n", Sites.DomainSeparator);

			GetInsertRight(dc, site, true);	// 权限验证

			dc.Sites.InsertOnSubmit(site);
			dc.SubmitChanges();

			// 记录日志
			Logs.Insert(dc, ResourceId, (int)PermissionCode.Insert, INFO_TYPE, site.SiteId.ToString(), PermissionCode.Insert.ToString(), site.SiteName);

			// 返回只读数据
			return insertedSite.FillByEntity(site);
		}
		#endregion



		#region Update
		private static readonly HashSet<string> _updatedExcludeColumns = typeof(Site).GetEntityColumnNames(new string[] {
				"SiteId"
			}, true);

		/// <summary>
		/// 修改站点。
		/// </summary>
		/// <param name="updatedSite">修改的站点。</param>
		/// <returns>修改的站点。</returns>
		public static Site Update(Site updatedSite)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Site site = dc.Sites.GetItem(updatedSite.SiteId);
			if (site == null)
				throw new ObjectNotExistsException(Res.Operation_ObjectNotExists);

			GetUpdateRight(dc, site, true);	// 权限验证

			site.FillByEntity(updatedSite, EntityColumnsSetType.Exclude, _updatedExcludeColumns);
			site.Domain = site.Domain == null ? null : site.Domain.Replace("\r\n", Sites.DomainSeparator);

			try
			{
				dc.SubmitChanges(ConflictMode.ContinueOnConflict);
			}
			catch (ChangeConflictException e)
			{
				foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
				{
					occ.Resolve(RefreshMode.KeepCurrentValues);
				}
			}

			// 记录日志
			Logs.Insert(dc, ResourceId, (int)PermissionCode.Update, INFO_TYPE, site.SiteId.ToString(), PermissionCode.Update.ToString(), site.SiteName);

			// 返回只读数据
			return updatedSite.FillByEntity(site);
		}
		#endregion



		#region Delete
		/// <summary>
		/// 删除站点。
		/// </summary>
		/// <param name="siteId">删除的站点标识 SiteId。</param>
		public static void Delete(int siteId)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Site site = dc.Sites.GetItem(siteId);
			if (site == null)
				throw new ObjectNotExistsException(Res.Operation_ObjectNotExists);

			GetDeleteRight(dc, site, true);	// 权限验证

			Delete(dc, site);
			dc.SubmitChanges();

			// 记录日志
			Logs.Insert(dc, ResourceId, (int)PermissionCode.Delete, INFO_TYPE, site.SiteId.ToString(), PermissionCode.Delete.ToString(), site.SiteName);
		}

		#region internal Delete
		internal static void Delete(GenericModuleDataContext dc, Site site)
		{
			PageBlocks.DeleteByParent(dc, site);	// 删除关联数据
			LinkClasses.DeleteByParent(dc, site);	// 删除关联数据
			VoteClasses.DeleteByParent(dc, site);	// 删除关联数据
			Modules.DeleteByParent(dc, site);	// 删除关联数据
			dc.Sites.DeleteOnSubmit(site);
		}
		#endregion
		#endregion
	}



	/// <summary>
	/// Sites 类对应操作权限部分。
	/// </summary>
	public static partial class Sites
	{
		#region GetInsertRight
		/// <summary>
		/// 获取当前用户是否有添加站点的权限。
		/// </summary>
		/// <param name="dc">数据容器。</param>
		/// <param name="site">添加的站点对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有添加站点的权限。</returns>
		public static bool GetInsertRight(GenericModuleDataContext dc, Site site, bool triggerException)
		{
			string userName = Users.CurrentUserName;
			int permissionCode = (int)PermissionCode.Insert;
			bool b = dc.AccessController.GetUserIsHasPermission<Site>(userName, site, ResourceId, permissionCode);

			if (triggerException && !b)
				throw new PermissionException(userName, site, ResourceId, permissionCode, Res.PermissionExceptionMessage);
			return b;
		}

		/// <summary>
		/// 获取当前用户是否有添加站点的权限。
		/// </summary>
		/// <param name="site">添加的站点对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有添加站点的权限。</returns>
		public static bool GetInsertRight(Site site, bool triggerException)
		{
			return GetInsertRight(new GenericModuleDataContext(), site, triggerException);
		}

		/// <summary>
		/// 获取当前用户是否有添加站点的权限。
		/// </summary>
		/// <param name="site">添加的站点对象。</param>
		/// <returns>布尔值表示当前用户是否有添加站点的权限。</returns>
		public static bool GetInsertRight(Site site)
		{
			return GetInsertRight(site, false);
		}
		#endregion



		#region GetUpdateRight
		/// <summary>
		/// 获取当前用户是否有更新站点的权限。
		/// </summary>
		/// <param name="dc">数据容器。</param>
		/// <param name="site">更新的站点对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有更新站点的权限。</returns>
		public static bool GetUpdateRight(GenericModuleDataContext dc, Site site, bool triggerException)
		{
			string userName = Users.CurrentUserName;
			int permissionCode = (int)PermissionCode.Update;
			bool b = dc.AccessController.GetUserIsHasPermission<Site>(userName, site, ResourceId, permissionCode);

			if (triggerException && !b)
				throw new PermissionException(userName, site, ResourceId, permissionCode, Res.PermissionExceptionMessage);
			return b;
		}

		/// <summary>
		/// 获取当前用户是否有更新站点的权限。
		/// </summary>
		/// <param name="site">更新的站点对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有更新站点的权限。</returns>
		public static bool GetUpdateRight(Site site, bool triggerException)
		{
			return GetUpdateRight(new GenericModuleDataContext(), site, triggerException);
		}

		/// <summary>
		/// 获取当前用户是否有更新站点的权限。
		/// </summary>
		/// <param name="site">更新的站点对象。</param>
		/// <returns>布尔值表示当前用户是否有更新站点的权限。</returns>
		public static bool GetUpdateRight(Site site)
		{
			return GetUpdateRight(site, false);
		}
		#endregion



		#region GetDeleteRight
		/// <summary>
		/// 获取当前用户是否有删除站点的权限。
		/// </summary>
		/// <param name="dc">数据容器。</param>
		/// <param name="site">删除的站点对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有删除站点的权限。</returns>
		public static bool GetDeleteRight(GenericModuleDataContext dc, Site site, bool triggerException)
		{
			string userName = Users.CurrentUserName;
			int permissionCode = (int)PermissionCode.Delete;
			bool b = dc.AccessController.GetUserIsHasPermission<Site>(userName, site, ResourceId, permissionCode);

			if (triggerException && !b)
				throw new PermissionException(userName, site, ResourceId, permissionCode, Res.PermissionExceptionMessage);
			return b;
		}

		/// <summary>
		/// 获取当前用户是否有删除站点的权限。
		/// </summary>
		/// <param name="site">删除的站点对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有删除站点的权限。</returns>
		public static bool GetDeleteRight(Site site, bool triggerException)
		{
			return GetDeleteRight(new GenericModuleDataContext(), site, triggerException);
		}

		/// <summary>
		/// 获取当前用户是否有删除站点的权限。
		/// </summary>
		/// <param name="site">删除的站点对象。</param>
		/// <returns>布尔值表示当前用户是否有删除站点的权限。</returns>
		public static bool GetDeleteRight(Site site)
		{
			return GetDeleteRight(site, false);
		}
		#endregion
	}




	/// <summary>
	/// Sites 类后台管理部分。
	/// </summary>
	public static partial class Sites
	{
		public static bool GetManageListRight()
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			return dc.AccessController.GetUserIsHasPermission<object>(Users.CurrentUserName, null, Sites.ResourceId, (int)Sites.PermissionCode.Update);
		}



		public static PaginationInfo<List<Site>> GetPaginationManageList(string keyword, int pageSize, int currentPage)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			var q = from p in dc.Sites
					select p;

			if (!string.IsNullOrEmpty(keyword))
				q = q.Where(p => p.SiteName.Contains(keyword));

			PaginationInfo<List<Site>> pageInfo = new PaginationInfo<List<Site>>();
			pageInfo.PageSize = pageSize;
			pageInfo.CurrentPage = currentPage;
			pageInfo.RecordCount = q.Count();
			pageInfo.Records = q.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
			return pageInfo;
		}
		
		public static PaginationInfo<List<Site>> GetPaginationSelectorList(string keyword, int[] siteIds, int pageSize, int currentPage)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			var q = from p in dc.Sites
					select p;

			if (!string.IsNullOrEmpty(keyword))
				q = q.Where(p => p.SiteName.Contains(keyword));

			if (siteIds != null)
			{
				if (siteIds.Length > 0)
					q = q.Where(p => siteIds.Contains(p.SiteId));
				else
					q = q.Where(p => 1 == 0);
			}

			PaginationInfo<List<Site>> pageInfo = new PaginationInfo<List<Site>>();
			pageInfo.PageSize = pageSize;
			pageInfo.CurrentPage = currentPage;
			pageInfo.RecordCount = q.Count();
			pageInfo.Records = q.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
			return pageInfo;
		}
	}
}